Reflective Print

별도의 출력 컴포넌트를 만들어서 사용할 수 있다.
각 클래스에서 멤버함수를 제거한다(베이스 클래스는 남겨둠)
struct Expression{
virtual ~Expression()= default;
};
struct ExpressionPrinter{
void print(DoubleExpression* de, ostringstream& oss) const {
oss<<de->value;
}
void print(AdditionExpression* ae, ostringstream& oss) const {
oss<<"(";
print(ae->left, oss);
oss<"+";
print(ae->right, oss);
oss<<")";
}
};
다형성을 활용하기 위해서는 베이스 클래스에 버추얼 속성을 가진 멤버함수가 있어야 하기 때문에
소멸자를 가상함수로 선언

위의 코드는 컴파일되지 않는다.
ae->left의 타입이 Expression이라는 사실은 알지만, DoubleExpression인지 AdditionExpression인지
알지 못한다.(print() 모호함)

C++은 컴파일 시점에 오버로딩이 결정된다.
반추적 방법
오버로딩을 사용하지 않고, 런타임 타임 체크를 명시적으로 구현
struct ExpressionPrinter{
void print(Expression* e){
if(auto de=dynamic_cast<DoubleExpression*>(e)){
oss<<de->value;
} else if(auto ae=dynamic_cast<AdditionExpression*>(e)){
oss<<"(";
print(ae->left, oss);
oss<<"+";
print(ae->right, oss);
oss<<")";
}
}
string str() const { return oss.str(); }
};
//
auto e=new AdditionExpression{
new DoubleExpression{1},
new AdditionExpression{
new DoubleExpression{2},
new DoubleExpression{3}
}
};
ExpressionPrinter ep;
ep.print(e);
cout<<ep.str()<<endl; // (1+(2+3))